iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0

Banner

物件池模式 Pool Pattern

物件池模式,每次的買賣都是致富的關鍵,致富不能只靠 40 顆大頭菜,靠的是放滿整座島的大頭菜,因此你需要有個島專門放大頭菜,放得滿滿的,到了關鍵時刻再把大頭菜拿出來賣。

UML

UML

實作

首先我們會需要把大頭菜定義出來,並且賦予幾些簡單的功能。

Turnips.php

/**
 * Class Turnips.
 */
class Turnips
{
    /**
     * @var int
     */
    protected $price;

    /**
     * @var int
     */
    protected $count;

    /**
     * Turnips constructor.
     *
     * @param int $price
     * @param int $count
     */
    public function __construct(int $price, int $count)
    {
        $this->price = $price;
        $this->count = $count;
    }

    /**
     * @return int
     */
    public function calculatePrice(): int
    {
        if (isset($this->price) && isset($this->count)) {
            return $this->price * $this->count;
        } else {
            return 0;
        }
    }
}

再來我們要做一個大頭菜池,而且要挖深,挖深呢,好處是有利於儲大頭菜,未來還可以養大頭菜,然後就可以把大頭菜通通丟進去。

TurnipsPool.php

use Countable;

/**
 * Class TurnipsPool.
 */
class TurnipsPool implements Countable
{
    /**
     * @var Turnips[]
     */
    protected $pool = [];

    /**
     * @var int
     */
    protected $total = 0;

    /**
     * @return Turnips
     */
    public function get(string $key = null): Turnips
    {
        if (isset($key)) {
            $turnips = $this->pool[$key];
            unset($this->pool[$key]);
        } else {
            $turnips = array_pop($this->pool);
        }

        $this->total -= $turnips->calculatePrice();

        return $turnips;
    }

    /**
     * 把大頭菜塞到池子裡
     *
     * @param Turnips $turnips
     * 
     * @return string
     */
    public function set(Turnips $turnips): string
    {
        $key = spl_object_hash($turnips);
        $this->total += $turnips->calculatePrice();
        $this->pool[$key] = $turnips;

        return $key;
    }

    /**
     * @return int
     */
    public function total(): int
    {
        return $this->total;
    }

    /**
     * @return int
     */
    public function count(): int
    {
        return count($this->pool);
    }
}

額外補充

Countable

繼承 Countable 這個類別可以使用 count() 這個方法,因此需要實作它。

class Countable {
    /* Methods */
    abstract public count ( void ) : int
}

測試

最後為了測試我們挖很深的大頭菜池是否能夠養大頭菜,所以我們有兩組測試要做:

  1. 測試是否能夠正常的新增 10 組大頭菜,並且把大頭菜拿出 2 組後,檢查池子裡面是否剩下 8 組大頭菜,然後比較一下拿出來的這 2 組是不是兩個不同的大頭菜,最後比較一下大頭菜池子裡的大頭菜價格是不是正確的。
  2. 測試是否能夠正常的新增 10 組大頭菜,並且把大頭菜拿出 1 組後,馬上把大頭菜丟回去池子裡,再從池子裡拿出 1 組大頭菜,檢查池子裡面是否剩下 9 組大頭菜,然後比較一下最後拿出來的這組,是不是就是一開始拿出來的那組大頭菜,最後比較一下大頭菜池子裡的大頭菜價格是不是正確的。

PoolPatternTest.php

/**
 * Class PoolPatternTest.
 */
class PoolPatternTest extends TestCase
{
    /**
     * 測試是否能夠正常的新增 10 組大頭菜,
     * 並且把大頭菜拿出 2 組後,檢查池子裡面是否剩下 8 組大頭菜,
     * 然後比較一下拿出來的這 2 組是不是兩個不同的大頭菜,
     * 最後比較一下大頭菜池子裡的大頭菜價格是不是正確的。
     * 
     * @test
     */
    public function test_can_set_new_turnips_and_get()
    {
        $pool = new TurnipsPool();
        for ($i = 0; $i < 10; $i++) {
            $turnips = new Turnips(100, 40);
            $pool->set($turnips);
        }

        $turnips1 = $pool->get();
        $turnips2 = $pool->get();

        $this->assertCount(8, $pool);
        $this->assertNotSame($turnips1, $turnips2);
        $this->assertEquals(32000, $pool->total());
    }

    /** 
     * 測試是否能夠正常的新增 10 組大頭菜,
     * 並且把大頭菜拿出 1 組後,馬上把大頭菜丟回去池子裡,
     * 再從池子裡拿出 1 組大頭菜,
     * 檢查池子裡面是否剩下 9 組大頭菜,
     * 然後比較一下最後拿出來的這組,是不是就是一開始拿出來的那組大頭菜,
     * 最後比較一下大頭菜池子裡的大頭菜價格是不是正確的。
     * 
     * @test
     */
    public function test_can_get_turnips_twice_when_set_it_first()
    {
        $pool = new TurnipsPool();
        for ($i = 0; $i < 10; $i++) {
            $turnips = new Turnips(100, 40);
            $pool->set($turnips);
        }

        $turnips1 = $pool->get();
        $pool->set($turnips1);

        $turnips2 = $pool->get();

        $this->assertCount(9, $pool);
        $this->assertSame($turnips1, $turnips2);
        $this->assertEquals(36000, $pool->total());
    }
}

最後測試的執行結果會獲得如下:

PHPUnit Pretty Result Printer 0.28.0 by Codedungeon and contributors.
==> Configuration: ~/php-design-pattern/vendor/codedungeon/phpunit-result-printer/src/phpunit-printer.yml

PHPUnit 9.2.6 by Sebastian Bergmann and contributors.


 ==> AbstractFactoryTest        ✔  ✔  ✔  ✔  
 ==> BuilderPatternTest         ✔  ✔  
 ==> FactoryMethodTest          ✔  ✔  ✔  ✔  
 ==> PoolPatternTest            ✔  ✔  
 ==> PrototypePatternTest       ✔  ✔  
 ==> SimpleFactoryTest          ✔  ✔  ✔  ✔  
 ==> SingletonPatternTest       ✔  
 ==> StaticFactoryTest          ✔  ✔  ✔  ✔  ✔  

Time: 00:00.050, Memory: 6.00 MB

OK (24 tests, 68 assertions)

完整程式碼

設計模式不難,找回快樂而已,以大頭菜為例。

參考文獻


上一篇
【PHP 設計模式大頭菜】建造者模式 Builder Pattern
下一篇
【PHP 設計模式大頭菜】轉接器模式 Adapter Pattern
系列文
設計模式不難,找回快樂而已,以大頭菜為例。30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言